package cn.gzzhome.utils

/**
 * 一个任务
 */
class Task {
    /**
     * 用于记录所有的任务
     */
    static Map<String, Task> allTask = [:]
    /**
     * 一些未知的依赖，这只能任务参数，不能使用
     */
    static Map<String, List<Task>> lazyDependTask = [:]
    /**
     * 任务名
     */
    String name
    /**
     * 所有依赖的任务列表
     */
    def dependOnList = [] as List<Task>

    /**
     * 所有依赖此任务的任务
     */
    def dependByList = [] as List<Task>

    /**
     * 任务依赖的路径
     */
    def paths = [] as List<String>

    def excludePaths = [] as List<String>
    /**
     * 备注
     */
    String remark

    /**
     * 依赖层级
     */
    int level = 0

    /**
     * 构建阶段列表
     */
    List<Move> moveList = []

    Set<String> moveNames = []

    /**
     * 执行用户的初始化方法
     * @param cb
     * @return
     */
    def init(String name, Closure cb) {
        println("初始化任务${name}")
        if (allTask.containsKey(name)) {
            throw new RuntimeException("${name}任务已经定义")
        }
        this.name = name;
        allTask[name] = this
        cb.delegate = this
        cb()
        println("${name}:更新依赖")
        updateDependTasks()
        println("${name}:刷新层级")
        try {
            refreshLevel()
        } catch (RuntimeException e) {
            throw new RuntimeException("round dep: ${e.getMessage()}")
        }

    }

    /**
     * 刷新依赖
     * @return
     */
    def updateDependTasks() {
        if (lazyDependTask.containsKey(name)) {
            Task[] tasks = lazyDependTask[name]
            this.dependByList += tasks
            tasks.each {
                it.dependOnList += this
                try {
                    refreshLevel()
                } catch (RuntimeException e) {
                    throw new RuntimeException("round dep: ${e.getMessage()}")
                }
            }
            lazyDependTask.remove(name)
        }
    }

    /**
     * 所有依赖的任务名
     * @param names
     */
    def dependOn(String... names) {
        names.each {
            if (allTask.containsKey(it)) {
                def task = allTask[it]
                this.dependOnList += task
                task.dependByList += this
            } else {
                if (!lazyDependTask.containsKey(it)) {
                    lazyDependTask[it] = []
                }
                lazyDependTask[it] += this
            }
        }
    }

    /**
     * 备注
     * @param v
     * @return
     */
    def remark(remark) {
        this.remark = remark
    }


    /**
     * 依赖的路径
     * @param paths
     * @return
     */
    def paths(String... paths) {
        this.paths += paths
    }

    /**
     * 不依赖的path
     * @param paths
     * @return
     */
    def excludePaths(String... paths) {
        this.excludePaths += paths
    }

    /**
     * 判断是否需要构建，如果不需要请重载此方法
     * @return
     */
    def needProcess() {
        return true
    }

    /**
     * 判断是否依赖于目标任务
     * @param task
     */
    def isDependOn(Task task) {
        if (this == task) {
            throw new RuntimeException("round dependance")
        }
        return dependOnList.contains(task) || dependOnList.any {
            it.isDependOn(task)
        }
    }

    /**
     * 判断是否被目标任务全副
     * @param task
     * @return
     */
    def isDependBy(Task task) {
        if (this == task) {
            throw new RuntimeException("round dependence")
        }
        return dependByList.contains(task) || dependByList.any {
            it.isDependBy(task)
        }
    }

    /**
     * 获取级别，注意：此方法使用动态记录，会比较耗时间，应该尽量少用或使用缓存
     * @return
     */
    def refreshLevel(Task ori = null) {
        if (dependOnList.size() == 0) {
            level = 0
        } else {
            if (this == ori) {
                throw new RuntimeException("${this.name}")
            } else {
                if (ori == null) {
                    ori = this
                }
                try {
                    def parent = dependOnList.max {
                        it.refreshLevel(ori)
                    }
                    def parentLevel = parent.level
                    level = parentLevel + 1
                } catch (RuntimeException e) {
                    throw new RuntimeException("${name}->${e.getMessage()}")
                }

            }
        }
        return level
    }

    /**
     * 执行步骤
     * @param name
     * @param callback
     */
    def move(String name, Closure callback) {
        if (moveNames.contains(name)) {
            throw new RuntimeException("重复的步骤名：${name}")
        }
        this.moveNames += name
        Move move = new Move()
        move.name = "${this.name} >> ${name}"
        move.task = this
        move.idx = moveList.size()
        move.callback = callback
        this.moveList += move
        return move
    }

    /**
     * 阻断的步骤
     * @param name
     * @param callback
     * @return
     */
    def blockMove(String name, Closure callback) {
        def move = move(name, callback)
        this.moveList.each { it.block = true }
        return move
    }

}
